import static org.junit.Assert.*;

import org.junit.Before;
import org.junit.Test;

import com.pavlinic.mylisp.Expression;
import com.pavlinic.mylisp.LispTestCase;
import com.pavlinic.mylisp.NullExpression;
import com.pavlinic.mylisp.repl.Bootstrapper;


public class ListFunctionsTest extends LispTestCase  {
  @Before public void bootstrap() {
    Bootstrapper.getInstance().bootstrap();
  }
  
  @Test public void cons() {
    final Expression expected = parse("(1 2 3 4)");
    final Expression got = eval("(cons (quote 1) (quote (2 3 4)))");
    assertEquals(expected, got);
  }
  
  @Test public void first() {
    final Expression expected = parse("1");
    final Expression got = eval("(first (quote (1 2 3)))");
    assertEquals(expected, got);
  }
  
  @Test public void rest() {
    final Expression expected = parse("(2 3)");
    final Expression got = eval("(rest (quote (1 2 3)))");
    assertEquals(expected, got);
  }
  
  @Test public void restOfOneElementListIsNull() {
    final Expression expected = NullExpression.INSTANCE;
    final Expression got = eval("(rest (quote (3)))");
    assertEquals(expected, got);
  }
  
  @Test public void langth() {
	  final Expression expected = parse("3");
	  final Expression got = eval("(length (quote (1 2 3)))");
	  assertEquals(expected, got);
  }
  
  @Test public void reduce() {
	  final Expression expected = parse("6");
	  final Expression got = eval("(reduce addTwo (quote (1 2 3)))");
	  assertEquals(expected, got);
  }
  
  @Test public void list() {
	  final Expression expected = parse("(1 2 3 4)");
	  final Expression got = eval("(list 1 2 3 4)");
	  assertEquals(expected, got);
  }
  
  @Test public void listWithNestedStuff() {
	  final Expression expected = parse("(1 2 7 5)");
	  final Expression got = eval("(list 1 2 (+ 3 4) 5)");
	  assertEquals(expected, got);
  }
  
  @Test public void assoc() {
	  final Expression expected = parse("(3 3)");
	  final Expression got = eval("(assoc 3 '((1 1) (2 2) (3 3)))");
	  assertEquals(expected, got);
  }
  
  @Test public void emptyTrue() {
	  final Expression expected = parse("true");
	  final Expression got = eval("(empty? '())");
	  assertEquals(expected, got);
  }
  
  @Test public void emptyFalse() {
	  final Expression expected = parse("false");
	  final Expression got = eval("(empty? '(1 2))");
	  assertEquals(expected, got);
  }
  
  @Test public void apply() {
	  final Expression expected = parse("3");
	  final Expression got = eval("(apply + '(1 2))");
	  assertEquals(expected, got);
  }
  
  @Test public void append() {
	  final Expression expected = parse("(1 2 3 4 5 6)");
	  final Expression got = eval("(append '(1) '(2 3) '(4 5 6))");
	  assertEquals(expected, got);
  }
}
